package juf.adapter;


import java.lang.annotation.Annotation;
import java.util.Collection;

import juf.Property;
import juf.Annotations.CustomAdapter;


/**Given a Property object representing a data source, AdapterFactory
 * creates and returns an appropriate Adapter to display that data source.
 * <p>
 * This is based on the data type by default, but will eventually have the logic 
 * to deal with annotations and xml config giving the user full control of 
 * the mapping of (data type) -> (component)
 * 
 * @author Dale Halliwell, Parul Sharma
 *
 */
public class AdapterFactory {

	/** Resolve an Adapter that can displaying the Property datasource
	 * @param datasource the source (field or accessor-pair) of the data, wrapped in a Property interface
	 * @return Adapter capable of displaying and/or updating the data source
	 * 
	 */
	@SuppressWarnings("unchecked")
	public static Adapter createAdapter(Property datasource){
		
		Class type = datasource.getType();
		
		//------------------------------------------------------------------------------------		
		//User-defined choice of adapter
		//find out if the user has specified an adapter in annotations
		//then find what adapter they mentioned, then use that adapter
		Annotation[] annotations = datasource.getAnnotations();
		for (Annotation a : annotations){
			if (a.annotationType().equals(CustomAdapter.class)){
				CustomAdapter annotation = (CustomAdapter) a;
				System.out.println("Custom Adapter selected for " + datasource.getName() + " : " + annotation.value()); //make it return the specified adapter
				//TODO could these mappings be loaded from an external source, or registerd by a configurator-type function?
				//..want to avoid the user having to modify AdapterFactory if they want to implement their own Adapter
				if (annotation.value().equals("GenericObjectAdapter")){
					return new GenericObjectAdapter(datasource);
				}
				else if (annotation.value().equals("JCheckBoxAdapter")){
					return new JCheckBoxAdapter(datasource);
				}	
				else if (annotation.value().equals("JDatePickerAdapter")){
					return new JDatePickerAdapter(datasource);
				}				
				else if (annotation.value().equals("JListAdapter")){
					return new JListAdapter(datasource);
				}				
				else if (annotation.value().equals("JTextFieldAdapter")){
					return new JTextFieldAdapter(datasource);
				}				
				else if (annotation.value().equals("JTreeAdapter")){
					return new JTreeAdapter(datasource);
				}


				else{
					//if it is not valid, write a debug message to the console, and go on to select the default adapter for that type
					System.out.println(annotation.value() + " is not a known Adapter. Have you registered your custom Adapter with AdapterFactory? Using default.");
				}
			}
		}
		
		//------------------------------------------------------------------------------------
		//The user has not specified a choice of adapter in the annotations
		//so we infer which default adapter to use by looking at the type of the field/method		
		
		if (type == java.util.Date.class)
			return new JDatePickerAdapter(datasource); //dates use the date picker adapter

		if (type == boolean.class || type == Boolean.class)
			return new JCheckBoxAdapter(datasource);  //checkbox to represent boolean values
		
		if (datasource.getValue() instanceof Collection)  
			return new JListAdapter(datasource); //collections use the JListAdapter by default
		
		if (datasource.getValue() instanceof Object[])  
			return new JTreeAdapter(datasource);	//arrays use the JTreeAdapter by default

		//seven of the eight Java primitive types default to textbox adapter (boolean defaults to checkbox)
		//the primitive class wrappers, String and Class special types also
		if (type == char.class || 
				type == int.class || 
				type == double.class || 
				type == byte.class || 
				type == long.class	|| 
				type == short.class ||
				type == float.class ||
				type == String.class || 
				type == Class.class ||
				type == Integer.class ||
				type == Double.class ||
				type == Float.class ||
				type == Byte.class || 
				type == Long.class || 
				type == Short.class
		
		)
			return new JTextFieldAdapter(datasource);	

		//------------------------------------------------------------------------------------
		
		//In all other cases, default to the generic object adapter
		else 
			return new GenericObjectAdapter(datasource); 	
	
	} //end createAdapter
	
	
}
